package org.formal.common.utils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.commons.lang3.StringUtils;

/**
 * 多线程下载文件
 * @version:1.0
 * @Description: RemoteDownUtils
 * @author: jiangyan 
 * @date: 2018年9月20日
 */
public class RemoteDownUtils {

	private final static int THREAD_COUNT = 5;
	
	/**
	 * 下载路径
	 */
	private String path;
	
	/**
	 *下载存放路径
	 */
	private String targetPath = "C:/upload";

	public RemoteDownUtils(String path) {
		this.path = path;
	}
	
	public RemoteDownUtils(String path, String targetPath) {
		this.path = path;
		this.targetPath = targetPath;
	}
	
	/**
	 * 多线程文件下载
	 * @param path 下载路径
	 */
	public void download() {
		try {
			URL url = new URL(path);
			HttpURLConnection connection =	(HttpURLConnection) url.openConnection();
			connection.setConnectTimeout(10000);
			connection.setRequestMethod("GET");
			int code = connection.getResponseCode();
			if(code == 200) {
				int length = connection.getContentLength();
				System.out.println("文件总字节大小" + length);
				//计算每个线程理论上下载的数量.
				int blockSize = length/THREAD_COUNT;
				//为每个线程分配任务
				for(int threadId = 0; threadId < THREAD_COUNT; threadId++){
					//线程开始下载的位置
					int startIndex = threadId * blockSize; 
					//线程结束下载的位置
					int endIndex = (threadId+1) * blockSize -1; 
					//如果是最后一个线程,将剩下的文件全部交给这个线程完成
					if(threadId == (THREAD_COUNT - 1)){  
						endIndex = length - 1;
					}
					new DownloadThread(threadId, startIndex, endIndex).start();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取下载文件的名称
	 * @param url
	 * @return
	 */
	private String getFileName(URL url){
		String fileName = url.getFile();
		int lastIndex = fileName.lastIndexOf("/");
		String subName = fileName.substring(lastIndex + 1);
		int  subIndex = subName.indexOf("?", lastIndex);
		if(subIndex > 0) {
			subName = subName.substring(0, subIndex);
		}
		if(StringUtils.isEmpty(subName) || subIndex == 0) {
			return "temp.txt";
		}
		return subName;
	}

	private class DownloadThread extends Thread {

		private int threadId;
		private int startIndex;
		private int endIndex;

		public  DownloadThread(int threadId, int startIndex, int endIndex) {
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
		}

		@Override
		public void run() {
			try {
				URL url = new URL(path);
				File downFile = new File(targetPath,"downRunnable_" + threadId + ".dt");
				RandomAccessFile downThreadStream  = new RandomAccessFile(downFile,"rwd");
				String startIndexStr = downThreadStream.readLine();
				if (StringUtils.isNoneBlank(startIndexStr)){  
					//设置文件每次起点   
					this.startIndex = Integer.parseInt(startIndexStr)-1;
				}
				HttpURLConnection connection = (HttpURLConnection) url.openConnection();
				connection.setRequestMethod("GET");
				connection.setConnectTimeout(10000);

				//设置分段下载的头信息。  Range:做分段数据请求用的。格式: Range bytes=0-1024  或者 bytes:0-1024
				connection.setRequestProperty("Range", "bytes="+ startIndex + "-" + endIndex);

				System.out.println("线程_"+threadId + "的下载起点是 " + startIndex + "  下载终点是: " + endIndex);
				System.out.println(connection.getResponseCode());
				//200：请求全部资源成功， 206代表部分资源请求成功
				if(connection.getResponseCode() == 206){
					//获取流
					InputStream inputStream = connection.getInputStream();
					//获取前面已创建的文件.
					RandomAccessFile randomAccessFile = new RandomAccessFile(
							new File(targetPath,getFileName(url)), "rw");
					//文件写入的开始位置.
					randomAccessFile.seek(startIndex);


					/*
					 * 将网络流中的文件写入本地
					 */
					byte[] buffer = new byte[1024];
					int length = -1;
					//记录本次下载文件的大小
					int total = 0;
					while((length = inputStream.read(buffer)) > 0){
						randomAccessFile.write(buffer, 0, length);
						total += length;
						/*
						 * 将当前现在到的位置保存到文件中
						 */
						downThreadStream.seek(0);
						downThreadStream.write((startIndex + total + "").getBytes("UTF-8"));
					}

					downThreadStream.close();
					inputStream.close();
					randomAccessFile.close();                   
					//删除临时文件
					cleanTemp(downFile);
					System.out.println("线程"+ threadId + "下载完毕");
				}else{
					System.out.println("响应码是" +connection.getResponseCode() + ". 服务器不支持多线程下载");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
	}

	/**
	 * 删除线程产生的临时文件
	 * @param file
	 */
	private synchronized void cleanTemp(File file){
		file.delete();
	}

	public static void main(String[] args) {
		new RemoteDownUtils("https://www.baidu.com/?tn=47018152_dg").download();
	}
}
